import 'package:edu/networks/common/base_response.dart';
import 'package:json_annotation/json_annotation.dart';

part 'user_response.g.dart';

/*
 * @Description: 用户简要信息
 */
@JsonSerializable()
class UserBrief {
  @JsonKey(name: 'id')
  int id;

  @JsonKey(name: 'type')
  String type;

  @JsonKey(name: 'name')
  String name;

  @JsonKey(name: 'gender')
  String? gender;

  @JsonKey(name: 'avatar')
  String? avatar;

  @JsonKey(name: 'created_at')
  DateTime createdAt;

  @JsonKey(name: 'purchasing_courses')
  List<int> purchasingCourses;

  @JsonKey(name: 'purchased_courses')
  List<int> purchasedCourses;

  UserBrief({
    required this.id,
    required this.type,
    required this.name,
    this.gender,
    this.avatar,
    required this.createdAt,
    this.purchasingCourses = const [],
    this.purchasedCourses = const [],
  });

  factory UserBrief.fromJson(Map<String, dynamic> json) =>
      _$UserBriefFromJson(json);

  Map<String, dynamic> toJson() => _$UserBriefToJson(this);

  /*
   * 1.方法参数均为可选参数（带?），允许只修改需要变更的属性
   * 2.使用??运算符实现 "如果传入新值则使用新值，否则保留原对象属性" 的逻辑
   * 3.返回一个新的 UserBrief 对象，原对象属性保持不变（ immutable 特性）
   */
  UserBrief copyWith({
    String? type,
    String? name,
    String? gender,
    String? avatar,
    DateTime? createdAt,
    int? learnedMinutes,
    List<int>? purchasingCourses,
    List<int>? purchasedCourses,
  }) {
    return UserBrief(
      id: id,
      type: type ?? this.type,
      name: name ?? this.name,
      gender: gender ?? this.gender,
      avatar: avatar ?? this.avatar,
      createdAt: createdAt ?? this.createdAt,
      purchasingCourses: purchasingCourses ?? this.purchasingCourses,
      purchasedCourses: purchasedCourses ?? this.purchasedCourses,
    );
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;

    return other is UserBrief &&
        other.id == id &&
        other.type == type &&
        other.name == name &&
        other.gender == gender &&
        other.avatar == avatar &&
        other.createdAt == createdAt &&
        other.purchasingCourses == purchasingCourses &&
        other.purchasedCourses == purchasedCourses;
  }

  @override
  int get hashCode =>
      id.hashCode ^
      type.hashCode ^
      name.hashCode ^
      gender.hashCode ^
      avatar.hashCode ^
      createdAt.hashCode ^
      purchasingCourses.hashCode ^
      purchasedCourses.hashCode;

  bool get isTeacher => type == 'teacher';
  bool get isAdmin => type == 'admin';
}

@JsonSerializable()
class UserBriefResponse extends BaseResponse {
  @JsonKey(name: 'token')
  String? token;
  @JsonKey(name: 'brief')
  UserBrief? brief;

  UserBriefResponse({
    required super.code,
    this.token,
    this.brief,
    super.message,
  });

  factory UserBriefResponse.fromJson(Map<String, dynamic> json) =>
      _$UserBriefResponseFromJson(json);

  Map<String, dynamic> toJson() => _$UserBriefResponseToJson(this);
}

/* 用户详细信息 */
@JsonSerializable()
class UserProfile extends UserBrief {
  @JsonKey(name: 'email')
  String? email;

  @JsonKey(name: 'phone_number')
  String? phoneNumber;

  @JsonKey(name: 'wechat_id')
  String? wechatId;

  @JsonKey(name: 'region')
  String? region;

  @JsonKey(name: 'region_code_array')
  List<String>? regionCodeList;

  @JsonKey(name: 'introduction')
  String? introduction;

  @JsonKey(name: 'profession')
  String? profession;

  @JsonKey(name: 'updated_at')
  DateTime updatedAt;

  UserProfile({
    required super.id,
    required super.type,
    required super.name,
    super.gender,
    super.avatar,
    required super.createdAt,
    super.purchasingCourses = const [],
    super.purchasedCourses = const [],
    this.email,
    this.phoneNumber,
    this.wechatId,
    this.region,
    this.regionCodeList,
    this.introduction,
    this.profession,
    required this.updatedAt,
  });

  factory UserProfile.fromJson(Map<String, dynamic> json) =>
      _$UserProfileFromJson(json);

  @override
  Map<String, dynamic> toJson() => _$UserProfileToJson(this);

  @override
  UserProfile copyWith({
    String? type,
    String? name,
    String? gender,
    String? avatar,
    DateTime? createdAt,
    int? learnedMinutes,
    List<int>? purchasingCourses,
    List<int>? purchasedCourses,
    String? email,
    String? phoneNumber,
    String? wechatId,
    String? region,
    List<String>? regionCodeList,
    String? introduction,
    String? profession,
    DateTime? updatedAt,
    int? version,
  }) {
    return UserProfile(
      id: id,
      type: type ?? this.type,
      name: name ?? this.name,
      gender: gender ?? this.gender,
      avatar: avatar ?? this.avatar,
      createdAt: createdAt ?? this.createdAt,
      purchasingCourses: purchasingCourses ?? this.purchasingCourses,
      purchasedCourses: purchasedCourses ?? this.purchasedCourses,
      email: email ?? this.email,
      phoneNumber: phoneNumber ?? this.phoneNumber,
      wechatId: wechatId ?? this.wechatId,
      region: region ?? this.region,
      regionCodeList: regionCodeList ?? this.regionCodeList,
      introduction: introduction ?? this.introduction,
      profession: profession ?? this.profession,
      updatedAt: updatedAt ?? this.updatedAt,
    );
  }

  UserBrief getUserBrief() {
    return UserBrief(
      id: id,
      type: type,
      name: name,
      gender: gender,
      avatar: avatar,
      createdAt: createdAt,
      purchasingCourses: purchasingCourses,
      purchasedCourses: purchasedCourses,
    );
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    return other is UserProfile &&
        other.id == id &&
        other.type == type &&
        other.name == name &&
        other.gender == gender &&
        other.avatar == avatar &&
        other.createdAt == createdAt &&
        other.email == email &&
        other.phoneNumber == phoneNumber &&
        other.wechatId == wechatId &&
        other.region == region &&
        other.regionCodeList == regionCodeList &&
        other.introduction == introduction &&
        other.profession == profession &&
        other.updatedAt == updatedAt &&
        other.purchasingCourses == purchasingCourses &&
        other.purchasedCourses == purchasedCourses;
  }

  @override
  int get hashCode =>
      super.hashCode ^
      email.hashCode ^
      phoneNumber.hashCode ^
      wechatId.hashCode ^
      region.hashCode ^
      regionCodeList.hashCode ^
      introduction.hashCode ^
      profession.hashCode ^
      updatedAt.hashCode;
}

@JsonSerializable()
class UserProfileResponse extends BaseResponse {
  @JsonKey(name: 'profile')
  UserProfile? profile;

  UserProfileResponse({this.profile, required super.code, super.message});

  factory UserProfileResponse.fromJson(Map<String, dynamic> json) =>
      _$UserProfileResponseFromJson(json);

  Map<String, dynamic> toJson() => _$UserProfileResponseToJson(this);
}

@JsonSerializable()
class UserProfileField {
  @JsonKey(name: 'id')
  int id;
  @JsonKey(name: 'field')
  String field;
  @JsonKey(name: 'value')
  String value;
  @JsonKey(name: 'list')
  List<String>? list;

  UserProfileField({
    required this.id,
    required this.field,
    required this.value,
    this.list,
  });

  factory UserProfileField.fromJson(Map<String, dynamic> json) =>
      _$UserProfileFieldFromJson(json);
  Map<String, dynamic> toJson() => _$UserProfileFieldToJson(this);
}

@JsonSerializable()
class UserProfileFieldResponse extends BaseResponse {
  @JsonKey(name: 'result')
  UserProfileField? result;

  UserProfileFieldResponse({required super.code, super.message, this.result});

  factory UserProfileFieldResponse.fromJson(Map<String, dynamic> json) =>
      _$UserProfileFieldResponseFromJson(json);
  Map<String, dynamic> toJson() => _$UserProfileFieldResponseToJson(this);
}

@JsonSerializable()
class Profession {
  @JsonKey(name: 'id')
  int id;
  @JsonKey(name: 'title')
  String title;

  Profession({required this.id, required this.title});

  factory Profession.fromJson(Map<String, dynamic> json) =>
      _$ProfessionFromJson(json);

  Map<String, dynamic> toJson() => _$ProfessionToJson(this);
}

@JsonSerializable()
class ProfessionResponse extends BaseResponse {
  @JsonKey(name: 'professions')
  List<Profession>? professions;

  ProfessionResponse({required super.code, super.message, this.professions});

  factory ProfessionResponse.fromJson(Map<String, dynamic> json) =>
      _$ProfessionResponseFromJson(json);

  Map<String, dynamic> toJson() => _$ProfessionResponseToJson(this);
}

@JsonSerializable()
class ChinaRegion {
  @JsonKey(name: 'code')
  String code;
  @JsonKey(name: 'name')
  String name;
  @JsonKey(name: 'level')
  int level;
  @JsonKey(name: 'category')
  int category;

  ChinaRegion({
    required this.code,
    required this.name,
    required this.level,
    required this.category,
  });

  factory ChinaRegion.fromJson(Map<String, dynamic> json) =>
      _$ChinaRegionFromJson(json);

  Map<String, dynamic> toJson() => _$ChinaRegionToJson(this);
}

@JsonSerializable()
class ChinaRegionResponse extends BaseResponse {
  @JsonKey(name: 'regions')
  List<ChinaRegion>? regions;

  ChinaRegionResponse({required super.code, super.message, this.regions});

  factory ChinaRegionResponse.fromJson(Map<String, dynamic> json) =>
      _$ChinaRegionResponseFromJson(json);

  Map<String, dynamic> toJson() => _$ChinaRegionResponseToJson(this);
}

@JsonSerializable()
class VerifyCodeStatus {
  @JsonKey(name: 'type')
  String type;
  @JsonKey(name: 'status')
  int status;
  @JsonKey(name: 'valid_minutes')
  int? validMinutes;

  VerifyCodeStatus({
    required this.type,
    required this.status,
    this.validMinutes,
  });

  factory VerifyCodeStatus.fromJson(Map<String, dynamic> json) =>
      _$VerifyCodeStatusFromJson(json);

  Map<String, dynamic> toJson() => _$VerifyCodeStatusToJson(this);
}

@JsonSerializable()
class VerifyCodeStatusResponse extends BaseResponse {
  @JsonKey(name: 'status')
  VerifyCodeStatus? status;

  VerifyCodeStatusResponse({required super.code, super.message, this.status});

  factory VerifyCodeStatusResponse.fromJson(Map<String, dynamic> json) =>
      _$VerifyCodeStatusResponseFromJson(json);

  Map<String, dynamic> toJson() => _$VerifyCodeStatusResponseToJson(this);
}
